package com.tyf.bookreader.manager;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.tyf.bookreader.constant.RedisConstants;
import com.tyf.bookreader.domain.BrComment;
import com.tyf.bookreader.domain.BrOrder;
import com.tyf.bookreader.domain.BrUserStarComment;
import com.tyf.bookreader.dto.CommentStarDto;
import com.tyf.bookreader.exception.BrException;
import com.tyf.bookreader.mapper.BrCommentMapper;
import com.tyf.bookreader.mapper.BrUserStarCommentMapper;
import com.tyf.bookreader.service.RedisService;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @Description 评论manager
 * @Author shallow
 * @Date 2023/4/3 20:18
 */
@Component
@Slf4j
public class CommentCacheManager {

    @Autowired
    private RedisService redisService;

    @Autowired
    private BrCommentMapper commentMapper;

    @Autowired
    private BrUserStarCommentMapper userStarCommentMapper;

    @Autowired
    private RedissonClient redissonClient;

    public Integer getStarsById(Long commentId){
        Integer starNum = (Integer) redisService.hGet(RedisConstants.COMMENT_STAR_NUM_CACHE_KEY, String.valueOf(commentId));
        if (Objects.nonNull(starNum)) {
            return starNum;
        }
        BrComment comment = commentMapper.selectById(commentId);
        redisService.hSet(RedisConstants.COMMENT_STAR_NUM_CACHE_KEY,String.valueOf(commentId),comment.getCommentStars(),RedisConstants.COMMON_CACHE_TIME);
        return comment.getCommentStars();
    }

    public CommentStarDto starsComment(Long commentId, Long userId){
        RLock lock = redissonClient.getLock(RedisConstants.REDISSON_LOCK_COMMENT + userId);
        CommentStarDto commentStarDto = new CommentStarDto();
        try {
            lock.lock();
            //判断是否点过赞
            boolean hasStared = hasStared(commentId, userId);
            //已点赞则取消点赞，点赞数-1
            if(hasStared){
                cancelStar(commentId,userId);
                commentStarDto.setMessage("取消点赞成功");
            }else{
                addStar(commentId,userId);
                commentStarDto.setMessage("点赞成功");
            }
            Integer stars = Integer.valueOf(redisService.hGet(RedisConstants.COMMENT_STAR_NUM_CACHE_KEY, String.valueOf(commentId)).toString());
            commentStarDto.setCommentStars(stars.longValue());
        } finally {
            lock.unlock();
        }
        Integer stars = Integer.valueOf(redisService.hGet(RedisConstants.COMMENT_STAR_NUM_CACHE_KEY, String.valueOf(commentId)).toString());
        commentStarDto.setCommentStars(stars.longValue());
        return commentStarDto;
    }

    protected void cancelStar(Long commentId, Long userId) {
        String relationKey = RedisConstants.COMMENT_STAR_RELATION_CACHE_KEY;
        RLock lock = redissonClient.getLock(RedisConstants.REDISSON_LOCK_COMMENT_MODIFY+commentId);
        try {
            lock.lock();
            Object starNum = redisService.hGet(RedisConstants.COMMENT_STAR_NUM_CACHE_KEY, String.valueOf(commentId));
            if (Objects.nonNull(starNum)){
                redisService.hDecr(RedisConstants.COMMENT_STAR_NUM_CACHE_KEY,String.valueOf(commentId),1L);
                redisService.hSet(relationKey,commentId +":"+ userId,1,RedisConstants.COMMON_CACHE_TIME);
                return;
            }
            Integer commentStars = commentMapper.selectById(commentId).getCommentStars();
            redisService.hSet(RedisConstants.COMMENT_STAR_NUM_CACHE_KEY,String.valueOf(commentId),commentStars,RedisConstants.COMMON_CACHE_TIME);
            redisService.hDecr(RedisConstants.COMMENT_STAR_NUM_CACHE_KEY,String.valueOf(commentId),1L);
            redisService.hSet(relationKey, commentId +":"+ userId,1,RedisConstants.COMMON_CACHE_TIME);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }


    }

    protected void addStar(Long commentId, Long userId){
        String relationKey = RedisConstants.COMMENT_STAR_RELATION_CACHE_KEY;
        RLock lock = redissonClient.getLock(RedisConstants.REDISSON_LOCK_COMMENT_MODIFY+commentId);
        try {
            lock.lock();
            Object starNum = redisService.hGet(RedisConstants.COMMENT_STAR_NUM_CACHE_KEY, String.valueOf(commentId));
            if (Objects.nonNull(starNum)){
                redisService.hIncr(RedisConstants.COMMENT_STAR_NUM_CACHE_KEY,String.valueOf(commentId),1L);
                redisService.hSet(relationKey,commentId +":"+ userId,0,RedisConstants.COMMON_CACHE_TIME);
                return;
            }
            Integer commentStars = commentMapper.selectById(commentId).getCommentStars();
            redisService.hSet(RedisConstants.COMMENT_STAR_NUM_CACHE_KEY,String.valueOf(commentId),commentStars,RedisConstants.COMMON_CACHE_TIME);
            redisService.hIncr(RedisConstants.COMMENT_STAR_NUM_CACHE_KEY,String.valueOf(commentId),1L);
            redisService.hSet(relationKey,commentId +":"+ userId,0,RedisConstants.COMMON_CACHE_TIME);
        } finally {
            lock.unlock();
        }

    }

    protected boolean hasStared(Long commentId,Long userId){
        //判断是否点过赞,redis中value为0为已点赞，value为1为未点赞
        String relationKey = RedisConstants.COMMENT_STAR_RELATION_CACHE_KEY;
        Integer flag = (Integer)redisService.hGet(relationKey, commentId+":"+userId);
        if(Objects.nonNull(flag)){
            return flag.equals(0);
        }
        //redis中没有数据，去数据库中查看关系
        BrUserStarComment userStarComment = userStarCommentMapper.selectOne(new LambdaQueryWrapper<BrUserStarComment>()
                .eq(BrUserStarComment::getCommentId, commentId)
                .eq(BrUserStarComment::getUserId, userId));
        if (Objects.isNull(userStarComment)) {
            //数据库没有数据，说明未点赞
            redisService.hSet(relationKey,commentId +":"+ userId,1,RedisConstants.COMMON_CACHE_TIME);
            return false;
        }
        //得到数据库数据，将更新后的数据放入缓存中
        Integer status = userStarComment.getStatus();
        redisService.hSet(relationKey,commentId +":"+ userId,status,RedisConstants.COMMON_CACHE_TIME);
        return status.equals(0);
    }
}
